﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Magellan.Routing
{
    public class RouteCollection
    {
        private readonly List<IRoute> _routes = new List<IRoute>();
        private readonly HashSet<string> _routeNames = new HashSet<string>();
        private readonly object _routesLock = new object();

        public void Register(Route route)
        {
            var name = route.Name;

            lock (_routesLock)
            {
                if (_routeNames.Contains(name))
                {
                    throw new InvalidRouteException(route, string.Format("A route with the name '{0}' has already been registered.", name));
                }

                route.Prepare();
                _routeNames.Add(name);
                _routes.Add(route);
            }
        }

        public RouteMatch MatchPathToRoute(string requestPath)
        {
            var failLog = new StringBuilder();

            lock (_routesLock)
            {
                foreach (var route in _routes)
                {
                    var match = route.MatchPathToRoute(requestPath);
                    if (match.Success)
                    {
                        return match;
                    }

                    failLog.AppendFormat("Route '{0}' did not match: {1}.", route.Name, match.FailReason).AppendLine();
                }
            }

            return RouteMatch.Failure(null, failLog.ToString());
        }

        public PathMatch MatchRouteToPath(RouteValueDictionary values)
        {
            var failLog = new StringBuilder();

            lock (_routesLock)
            {
                foreach (var route in _routes)
                {
                    var match = route.MatchRouteToPath(values);
                    if (match.Success)
                    {
                        return match;
                    }

                    failLog.AppendFormat("Route '{0}' did not match: {1}.", route.Name, match.FailReason).AppendLine();
                }
            }

            return PathMatch.Failure(null, failLog.ToString());
        }
    }
}